local UI = SecretaryUI

local Table_DefaultSavedVariables = {
	header_height = 18,
	height = 14,
	width = {},
}

local function Table_OnCellClick (self, row, col)
	ChatFrame1:AddMessage("SecretaryUI: clicked on "..row..", "..col)
end

local function Table_OnCellDoubleClick (self, row, col)
end

local function Table_OnCellEnter(self, row, col)
end

local function Table_OnCellLeave(self, row, col)
end

local function Table_GetHeaderDesc(self, col)
	return self.desc[col]
end

local function Table_OnHeaderClick(self, col)
	if self.sort_col == col then
		self.sort_reversed = not self.sort_reversed
	else
		self.sort_col = col
		self.sort_reversed = false
	end
	self:Sort()
	self:Redraw()
end

local function Table_OnHeaderDragStart(self, col)
	local drag = self:GetHeaderFrame(col).drag
	self.drag = drag
	drag:StartMoving()
end

local function Table_OnHeaderDragStop(self)
	self.drag:StopMovingOrSizing()
end

local function Table_GetNumRows(self)
	return #self.data
end

local function Table_GetNumColumns(self)
	return #self.desc
end

local function Table_GetHeaderFrame(self, col)
	return self.headers[col]
end

local function Table_GetRowHeight(self, row)
	return self.sv.height
end

local function Table_GetHeaderHeight(self)
	return self.sv.header_height
end

local function Table_GetColumnWidth(self, col)
	return self.sv.width[col] or self.sv.default_width or 40 -- self.headers[col].text:GetTextWidth()
end

local function Table_GetRowOffset(self, row)
	return self.sv.header_height + self.sv.height * (row - 1)
end

local function Table_GetColumnOffset(self, col)
	local offset = 0
	for i = 1, col - 1 do
		offset = offset + self:GetColumnWidth(i)
	end
	return offset
end

local function Table_GetTableWidth(self)
	return self:GetColumnOffset(self:GetNumColumns() + 1)
end

local function Table_GetTableHeight(self)
	return self:GetRowOffset(self:GetNumRows() + 1)
end

local clone
do
	local function real_clone (data, cache)
		if type(data) ~= "table" then
			return data
		elseif cache[data] then
			return cache[data]
		end
		local r = {}
		cache[data] = r
		for k, v in pairs(data) do
			r[real_clone(k, cache)] = real_clone(v, cache)
		end
		return r
	end
	clone = function (data) return real_clone(data, {}) end
end

local function Table_Initialize(self, desc, data, sv)
	self.data = clone(data)
	self.desc = clone(desc)
	self.sv = sv or clone(Table_DefaultSavedVariables)
	self.headers = {}
	self.rows = {}
	self.sort_col = 1
	self.sort_reversed = false
	self:Sort()
end

local function Table_Layout(self, parent)
	local frame = self.frame
	if not frame then
		frame = CreateFrame("Frame", parent:GetName().."Table", parent)
		self.frame = frame
		frame.object = self
		frame:SetBackdrop({
			bgFile = "Interface\\TutorialFrame\\TutorialFrameBackground",
			edgeFile = "Interface\\Tooltips\\UI-Tooltip-Border",
			tile = true,
			edgeSize = 16,
			tileSize = 32,
			insets = {
				left = 5,
				right = 5,
				top = 5,
				bottom = 5
			}
		})
		frame:EnableMouse(true)
	end
	for col = 1, self:GetNumColumns() do
		local header = self.headers[col]
		if not header then
			header = UI.MakeHeaderButton(frame, col)
			self.headers[col] = header
		end
	end
	for row = 1, self:GetNumRows() do
		local rowframe = self.rows[row]
		if not rowframe then
			rowframe = UI.MakeRow(frame, row)
			self.rows[row] = rowframe
		end
		rowframe:Layout()
	end
	self:Redraw()
	frame:ClearAllPoints()
	frame:SetPoint("CENTER")
	-- frame:SetPoint("BOTTOMRIGHT", self.rows[self:GetNumRows()].cells[self:GetNumColumns()]) -- ouch
	frame:SetWidth(self:GetTableWidth())
	frame:SetHeight(self:GetTableHeight())
	for _, header in ipairs(self.headers) do
		header:Layout()
	end
end

local function Table_Sort(self)
	local col = self.sort_col
	local sort
	if not self.sort_reversed then
		sort = function (a, b)
			return a[col] < b[col]
		end
	else
		sort = function (a, b)
			return a[col] > b[col]
		end
	end
	table.sort(self.data, sort)
end

local function Table_Redraw(self)	
	for col, desc in ipairs(self.desc) do
		local header = self.headers[col]
		header:SetText(desc)
		if col == self.sort_col then
			header.icon:SetTexture(self.sort_reversed and 
				"Interface\\Buttons\\UI-ScrollBar-ScrollUpButton-Up" or
				"Interface\\Buttons\\UI-ScrollBar-ScrollDownButton-Up")
			header.icon:Show()
		else
			header.icon:Hide()
		end
	end
	local nrows, ncols = self:GetNumRows(), self:GetNumColumns()
	for row = 1, nrows do
		local data = self.data[row]
		local rowframe = self.rows[row]
		for col = 1, ncols do
			local cell = rowframe.cells[col]
			cell:SetText(data[col])
		end
	end
end

local table_mt = {
	__index = {
		-- Cell
		OnCellClick = Table_OnCellClick,
		OnCellDoubleClick = Table_OnCellDoubleClick,
		OnCellEnter = Table_OnCellEnter,
		OnCellLeave = Table_OnCellLeave,
		-- HeaderButton
		GetHeaderDesc = Table_GetHeaderDesc,
		OnHeaderClick = Table_OnHeaderClick,
		-- HeaderDrag
		OnHeaderDragStart = Table_OnHeaderDragStart,
		OnHeaderDragStop = Table_OnHeaderDragStop,

		-- Table
		GetNumRows = Table_GetNumRows,
		GetNumColumns = Table_GetNumColumns,
		GetHeaderFrame = Table_GetHeaderFrame,
		GetRowHeight = Table_GetRowHeight,
		GetColumnWidth = Table_GetColumnWidth,
		GetRowOffset = Table_GetRowOffset,
		GetColumnOffset = Table_GetColumnOffset,
		GetTableWidth = Table_GetTableWidth,
		GetTableHeight = Table_GetTableHeight,
		GetHeaderHeight = Table_GetHeaderHeight,
		
		-- Initialize and Layout
		Initialize = Table_Initialize,
		Layout = Table_Layout, -- Layout the sub-frames
		Sort = Table_Sort, -- sort the data
		Redraw = Table_Redraw, -- redraw the data in the cells
	},
}

local function MakeTableObject()
	return setmetatable({}, table_mt)
end

UI.MakeTableObject = MakeTableObject